/*
 *  Borum, Boolean rule manipulator.
 *  Copyright (C) 2009 Jon Lennersten, Johan Hedin, Daniel Rosenberg
 *
 *  This file is part of Borum.
 *
 *  Borum is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Lesser General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  Borum is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public License
 *  along with Borum.  If not, see <http://www.gnu.org/licenses/>.
 */

package com.mawell.borum;

import net.antonioshome.swing.treewrapper.DeepCopyNode;

import javax.swing.*;
import javax.swing.tree.DefaultTreeCellRenderer;
import javax.swing.tree.TreeCellRenderer;
import javax.swing.tree.TreeNode;
import javax.swing.tree.TreePath;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.Enumeration;

public class DisplayHitCountRuleView extends JPanel {

    private Rule rule = new Rule();

    private Translation trans;
    private RuleModel model;

    private JTree tree;

    public DisplayHitCountRuleView(Rule rule, Translation trans, Object translationForTerms) {
        OperandNode rootNode = rule.getRootNode();
        rootNode.setTrans(trans);
        for(OperandProperty op : rootNode.getProperties()) {
            op.setTranslationForProperty(trans);
        }
        RuleModel model = new RuleModel();

        recursiveInsertNode(rootNode, trans, translationForTerms);
        TreeModel tm = new TreeModel(rootNode);

        model.insertNewModel(tm);

        setRule(rule);
        setName(rule.getName());
        setLocked(rule.isLocked());
        setSelected(rule.isSelected());

        this.model = model;
        this.trans = trans;
        this.setLayout(new GridBagLayout());
        init();
     }

    public RuleModel getModel() {
        return model;
    }

    public void setModel(RuleModel model) {
        this.model = model;
    }

    public Translation getTrans() {
        return trans;
    }

    public void setTrans(Translation trans) {
        this.trans = trans;
    }

    public Rule getRule() {
        TreeModel tm = getModel().getCurrentTreeModel();
        OperandNode rootNode = (OperandNode) tm.getRoot();
        recursively(rootNode);

        rule.setRootNode(rootNode);
        return rule;
    }

    public void recursively(OperandNode aNode) {
        aNode.setOps(new ArrayList<OperandNode>());
        aNode.setTerms(new ArrayList<Term>());
        Enumeration e = aNode.children();

        while(e.hasMoreElements()) {
            Object node = e.nextElement();
            if(node instanceof OperandNode) {
                recursively((OperandNode) node);
                aNode.getOps().add((OperandNode) node);
            } else {
                aNode.getTerms().add((Term) node);
            }
        }
    }

    public void setRule(Rule rule) {
        this.rule = rule;
    }

    public String getName() {
        if(rule == null) {
            return "";
        }
        return rule.getName();
    }

    public void setName(String name) {
        rule.setName(name);
    }

    public boolean isNewRule() {
        return rule.isNewRule();
    }

    public void setNewRule(boolean newRule) {
        rule.setNewRule(newRule);
    }

    public boolean isEdited() {
        return rule.isEdited();
    }

    public void setEdited(boolean edited) {
        rule.setEdited(edited);
    }

    public boolean isLocked() {
        return rule.isLocked();
    }

    public void setLocked(boolean locked) {
        rule.setLocked(locked);
    }

    public boolean isDeleted() {
        return rule.isDeleted();
    }

    public void setDeleted(boolean deleted) {
        rule.setDeleted(deleted);
    }

    public boolean isSelected() {
        return rule.isSelected();
    }

    public void setSelected(boolean selected) {
        rule.setSelected(selected);
    }

    public void expandAll(boolean expand) {
        TreeNode root = (TreeNode) tree.getModel().getRoot();

        // Traverse tree from root
        expandAll(tree, new TreePath(root), expand);
    }

    private void expandAll(JTree tree, TreePath parent, boolean expand) {
        // Traverse children
        TreeNode node = (TreeNode) parent.getLastPathComponent();
        if(node.getChildCount() >= 0) {
            Enumeration e = node.children();
            while(e.hasMoreElements()) {
                TreeNode n = (TreeNode) e.nextElement();
                TreePath path = parent.pathByAddingChild(n);
                expandAll(tree, path, expand);
            }
        }

        if(expand) {
            tree.expandPath(parent);
        } else {
            tree.collapsePath(parent);
        }
    }

    private void recursiveInsertNode(OperandNode node, Translation trans, Object translationForTerms) {
        if(node.getOps() != null) {
            for(OperandNode n : node.getOps()) {
                n.setTrans(trans);
                for(OperandProperty op : n.getProperties()) {
                    op.setTranslationForProperty(trans);
                }
                node.insert(n, node.getChildCount());
                recursiveInsertNode(n, trans, translationForTerms);
            }
        }
        if(node.getTerms() != null) {
            for(Term t : node.getTerms()) {
                t.setTranslationForTerm(translationForTerms);
                node.insert(t, node.getChildCount());
            }
        }
    }

    private void init() {
        addButtons();
        addScroller();
    }

    private void addButtons() {
        JPanel buttonPanel = new JPanel();

        JLabel expandLabel;
        java.net.URL url = DisplayHitCountRuleView.class.getResource("/icons/arrow_out.png");
        ImageIcon imageIcon = new ImageIcon(url);
        expandLabel = new JLabel(imageIcon);
        expandLabel.setToolTipText(trans.getLabelExpand());
        expandLabel.addMouseListener(new MouseAdapter() {
            public void mouseClicked(MouseEvent e) {
                expandAll(true);
            }
        });
        buttonPanel.add(expandLabel);

        JLabel collapseLabel;
        url = DisplayHitCountRuleView.class.getResource("/icons/arrow_in.png");
        imageIcon = new ImageIcon(url);
        collapseLabel = new JLabel(imageIcon);
        collapseLabel.setToolTipText(trans.getLabelCollapse());
        collapseLabel.addMouseListener(new MouseAdapter() {
            public void mouseClicked(MouseEvent e) {
                expandAll(false);
            }
        });
        buttonPanel.add(collapseLabel);

        GridBagConstraints c = new GridBagConstraints();
        c.anchor = GridBagConstraints.NORTHWEST;
        c.weightx = 0; // add horizontal space to this component
        c.weighty = 0; // add vertical space to this component
        c.gridwidth = GridBagConstraints.REMAINDER; // end of row
        c.gridheight = 1;
        c.fill = GridBagConstraints.NONE; // fill vertically and horizontally if bigger than expected
        this.add(buttonPanel, c);
    }

    private void addScroller() {

        if(model.getCurrentTreeModel() == null) {
            OperandNode rootNode = new OperandNode(OperandType.AND);
            rootNode.setTrans(trans);
            for(OperandProperty op : rootNode.getProperties()) {
                op.setTranslationForProperty(trans);
            }
            model.insertNewModel(new TreeModel(rootNode));

            tree = new JTree(model.getCurrentTreeModel());
        } else {
            tree = new JTree(model.getCurrentTreeModel());
        }

        tree.setCellRenderer(new CellRenderer());
        tree.setAutoscrolls(true);

        JScrollPane scroller = new JScrollPane();
        scroller.setViewportView(tree);
        GridBagConstraints c = new GridBagConstraints();
        c.anchor = GridBagConstraints.NORTHWEST;
        c.weightx = 1; // add horizontal space to this component
        c.weighty = 1; // add vertical space to this component
        c.gridwidth = GridBagConstraints.REMAINDER; // end of row
        c.gridheight = 1;
        c.fill = GridBagConstraints.BOTH; // fill vertically and horizontally if bigger than expected

        this.add(scroller, c);
    }

    private static class CellRenderer implements TreeCellRenderer {
      private Color darkRed = new Color(180,0,0);
        private Color darkGreen = new Color(0,150,0);

      private DefaultTreeCellRenderer defRenderer = new DefaultTreeCellRenderer();

      public Component  getTreeCellRendererComponent(JTree tree,
          Object value, boolean selected, boolean expanded,
          boolean leaf, int row, boolean hasFocus) {

          Component comp = defRenderer.getTreeCellRendererComponent(tree, value, selected, expanded, leaf, row, hasFocus);
          if(value instanceof DeepCopyNode) {
              DeepCopyNode node = (DeepCopyNode)value;
              switch(node.getHitCount()) {
                  case -1:
                      comp.setForeground(Color.BLACK);
                      break;
                  case 0:
                      comp.setForeground(darkRed);
                      ((JLabel)comp).setText(((JLabel)comp).getText()+" (0)");
                    break;
                  default:
                      comp.setForeground(darkGreen);
                      ((JLabel)comp).setText(((JLabel)comp).getText()+" ("+node.getHitCount()+")");
              }
          }
          return comp;
      }
    }

}